Aggiornamento dello stato

GCGiuseppe Crescitelli

L’aggiornamento dello stato è uno degli aspetti più critici di React, perché influisce direttamente su rendering, performance e prevedibilità del comportamento dei componenti. Comprendere come React gestisce gli aggiornamenti, la differenza tra merge e replace e l’uso corretto delle funzioni updater è fondamentale per scrivere codice affidabile.

Come React aggiorna lo stato

In React lo stato rappresenta un’istantanea dei dati in un determinato momento. Quando lo stato viene aggiornato, React non modifica direttamente il valore esistente, ma crea una nuova versione dello stato e pianifica un nuovo rendering del componente.

Gli aggiornamenti di stato sono asincroni e possono essere batchati, cioè raggruppati, per ottimizzare le prestazioni. Questo significa che non è garantito che lo stato sia aggiornato immediatamente dopo una chiamata a setState o al setter di useState.

Merge vs replace nello stato

Il comportamento dell’aggiornamento dello stato cambia in base al tipo di componente: classi o componenti funzionali.

Aggiornamento dello stato nelle classi: merge

Nei componenti a classe, l’aggiornamento dello stato avviene tramite setState. Quando si passa un oggetto a setState, React esegue un merge superficiale tra il nuovo oggetto e lo stato esistente.

Esempio:

this.state = {
  name: "Mario",
  age: 30,
};

this.setState({
  age: 31,
});

Dopo l’aggiornamento, lo stato risultante sarà:

{
  name: "Mario",
  age: 31
}

Solo le proprietà specificate vengono aggiornate, le altre restano invariate. Il merge è superficiale, quindi per oggetti annidati è necessario gestire manualmente la copia dei livelli interni.

Aggiornamento dello stato nei componenti funzionali: replace

Nei componenti funzionali, useState non esegue alcun merge automatico. Il valore passato al setter sostituisce completamente lo stato precedente.

Esempio:

const [user, setUser] = useState({
  name: "Mario",
  age: 30,
});

setUser({
  age: 31,
});

Il nuovo stato sarà:

{
  age: 31;
}

La proprietà name viene persa perché lo stato viene rimpiazzato. Per mantenere le altre proprietà è necessario copiarle esplicitamente.

Esempio corretto:

setUser({
  ...user,
  age: 31,
});

Questo approccio rende il comportamento più esplicito e coerente con i principi di immutabilità.

Implicazioni pratiche di merge e replace

Il merge automatico nelle classi può sembrare più comodo, ma può nascondere errori, soprattutto con strutture di stato complesse. Il replace nei componenti funzionali obbliga a essere espliciti su cosa viene mantenuto e cosa viene modificato, riducendo ambiguità e bug.

Per questo motivo, anche quando si lavora con classi, è buona pratica trattare lo stato come immutabile e aggiornare esplicitamente le strutture annidate.

Funzioni updater

Le funzioni updater permettono di aggiornare lo stato basandosi sul valore precedente. Sono fondamentali quando il nuovo stato dipende dal vecchio, specialmente in presenza di aggiornamenti asincroni o batchati.

Problema degli aggiornamenti basati sullo stato corrente

Esempio errato:

setCount(count + 1);
setCount(count + 1);

Il risultato finale potrebbe essere un incremento di 1 invece di 2, perché entrambe le chiamate usano lo stesso valore di count.

Uso corretto della funzione updater

La funzione updater riceve lo stato precedente come argomento e restituisce il nuovo stato.

setCount((prevCount) => prevCount + 1);
setCount((prevCount) => prevCount + 1);

In questo caso il risultato sarà sempre corretto, perché ogni aggiornamento si basa sul valore più recente.

Funzioni updater con oggetti

Le funzioni updater sono particolarmente utili con oggetti e array.

setUser((prevUser) => ({
  ...prevUser,
  age: prevUser.age + 1,
}));

Questo approccio garantisce che l’aggiornamento sia coerente anche se React raggruppa più setState.

Funzioni updater nei componenti a classe

Anche setState nelle classi supporta una funzione updater.

this.setState((prevState) => ({
  counter: prevState.counter + 1,
}));

L’uso della funzione updater è consigliato ogni volta che il nuovo stato dipende dal precedente, indipendentemente dal tipo di componente.

Linee guida per l’aggiornamento dello stato

Aggiornare sempre lo stato in modo immutabile, evitando modifiche dirette. Usare il merge automatico delle classi con consapevolezza, soprattutto con oggetti annidati. Ricordare che useState sostituisce completamente lo stato. Utilizzare le funzioni updater quando il nuovo stato dipende da quello precedente. Evitare di leggere immediatamente lo stato dopo un aggiornamento, perché potrebbe non essere ancora sincronizzato.

Una gestione corretta dell’aggiornamento dello stato rende i componenti più prevedibili, riduce bug difficili da tracciare e migliora la qualità complessiva dell’applicazione React.